package org.njo.webapp.templates.action;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.PageContext;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.ho.yaml.Yaml;
import org.njo.commons.lang.KeyUtil;
import org.njo.webapp.root.utility.SystemContext;
import org.njo.webapp.templates.config.ConfigLoadHelper;
import org.njo.webapp.templates.config.PatternConfig;
import org.njo.webapp.templates.config.TemplateConfig;
import org.njo.webapp.templates.taglib.Functions;

/**
 * 
 * 
 * 
 * 
 * @author yu.peng
 */
public class TemplatesGeneratorAction extends Action {

	public final static String GENERATOR_ACTION_PATH_PREFIX = "/templates.";
	
    // --------------------------------------------------------- Public Methods

    /**
     * 生成器控制Action.
     * 
     * 所有的模版做生成操作时,都需要提交到这个Action. 这个Action会按照以下的步骤处理.
     * 1,加载配置信息.注意:这个步骤只在第一次运行时执行.
     * 
     * 2,取得请求路径,并根据请求路径取得(模版集合)配置信息. 并以'pconfig'为key,保存到request属性中.
     * 这个步骤中有一个分支,就是如果没有正确找到(匹配) 到合适的模版配置信息,需要返回404错误,告知用户没有找到模版.
     * 
     * 3,计算取得输出路径.并以'ddpath'为key,保存到request属性中. 注意:这个路径将作为生成结果的根目录.
     * 
     * 4,备份请求参数. 以'reparam'为key,将请求参数保存成String形式.
     * 以'rparamvalues'为key,将请求参数保存成String[](数组)形式.
     * 
     * 5,TODO,转发或include,'controller.jsp',生成结果.
     * memo:如果使用include时需要,包装response.并需要保存生成的文件列表.
     * 
     * 6,压缩生成结果.将压缩后的文件名,以''为key,保存在request属性中.
     * 
     * 7,转发到生成成功画面.并在画面上输出生成的文件列表,以及下载连接.
     * 
     * 
     * 注意:本应该将一些控制代码写在这个Action中,而非controller.jsp中,
     * 是由于在模版的参数中需要使用一些参数,在jsp中可以使用el来达到这个目的.
     * 比如:在配置输出文件时,可以这样配置dest='/src/${package}/${var1}Form.java'
     * 通过el转换求值就可以得到动态的报名和文件名. 在Action中不能使用el,在controller.jsp的控制代码是必须的,
     * 不能转移到Action(java)程序中.因为在那里得不到pageContext.
     * 
     * Process the specified HTTP request, and create the corresponding HTTP
     * response (or forward to another web component that will create it).
     * Return an <code>ActionForward</code> instance describing where and how
     * control should be forwarded, or <code>null</code> if the response has
     * already been completed.
     *
     * @param mapping  The ActionMapping used to select this instance
     * @param form     The optional ActionForm bean for this request (if any)
     * @param request  The HTTP request we are processing
     * @param response The HTTP response we are creating
     * @throws Exception if the application business logic throws
     *                   an exception
     */
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        request.setAttribute("pgid", "XXX");
        
        ServletContext context = this.getServlet().getServletContext();
        
        // 读取配置信息到ServletContext中.配置文件需要在第一次请求时，加载到ServletContext中
        ConfigLoadHelper helper = ConfigLoadHelper.getInstance();
        if (!helper.isLoaded(context)) {
            String config_file_paths = mapping.getParameter();
            helper.loadConfig(context, config_file_paths);
        }

        // 根据请求路径,取得该路径对应的配置信息.分析path,取得正确模版集合(pattern),并取得配置信息
        String patternId = getPatternId(mapping);
        PatternConfig patternConfig = ConfigLoadHelper.getInstance().getPatternConfig(context, patternId);

        if (patternConfig != null) {
            JspFactory _jspxFactory = null;
            PageContext _jsp_page_context = null;
            try {
                _jspxFactory = JspFactory.getDefaultFactory();
                _jsp_page_context = _jspxFactory.getPageContext(this
                        .getServlet(), request, response, null, true, 8192,
                        true);

                request.setAttribute("pconfig", patternConfig);
                // 设定输出路径.输出输出目录,作为模版的输出目录
                String OUT_ROOT_PATH = SystemContext.getProperty("download.realpath","/opt");
                String folderName = KeyUtil.getUniqueKey();
                String outPath = OUT_ROOT_PATH + "/" + folderName;
                String zipFileName = folderName + ".zip";
                String DOWNLOAD_PATH = SystemContext.getProperty("download.path","/download");
                String DOWNLOAD_URL = DOWNLOAD_PATH + "/" + zipFileName;

                Map<String, TemplateConfig> templateConfigs = patternConfig
                        .getTemplateConfigs();
                Iterator<Map.Entry<String, TemplateConfig>> iterator = templateConfigs
                        .entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, TemplateConfig> entry = iterator.next();
                    TemplateConfig tconfig = entry.getValue();
                    request.setAttribute("tconfig", tconfig);
                    // 1, 执行表达式转换取得模版源src[输入文件(模版文件)]
                    String src = (String) Functions.evaluate(tconfig.getSrc(),
                            _jsp_page_context);
                    // 2, 执行表达式转换取得模版输出目标
                    String dest = (String) Functions.evaluate(
                            tconfig.getDest(), _jsp_page_context);

                    // 3, 执行模版,输出文件 TODO,转换完毕后,可能需要格式化
                    Functions.transform(src, dest, outPath, tconfig.isOutit(),
                            patternConfig.getCharset(), _jsp_page_context);
                    // 4, TODO:执行格式化
                    if (tconfig.isOutit() && tconfig.getFormatter() != null) {

                    }
                }
                // 压缩文件
                Functions.zip(new File(outPath), new File(OUT_ROOT_PATH, zipFileName));

                // 下载页面
                request.setAttribute("exportFile", DOWNLOAD_URL);
                return (new ActionForward("/exportfieldset.tiles", false));

            } finally {
                if (_jspxFactory != null)
                    _jspxFactory.releasePageContext(_jsp_page_context);
            }
        } else {
            // TODO 404 没有照到指定的模版.
            response.getWriter().print("404 没有照到指定的模版.");
            return null;
        }
    }

    /**
     * 根据ActionMapping的path取得patternId.
     * 
     * @param mapping
     * @return
     */
    private String getPatternId(ActionMapping mapping) {
        String path = mapping.getPath();
        String patternId = path.substring(GENERATOR_ACTION_PATH_PREFIX.length());
        return patternId;
    }
    
    

}
